package com.primi.chen.security.rsa;

import lombok.Data;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import java.io.StringReader;
import java.security.cert.Certificate;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Objects;

/**
 * Create AT 2020/3/6 12:02:12:02
 *
 * @author Primi.Chen(Chenxiangxu)
 */
@Data
public class EkycVerification {

    public static final String SIGNATURE_TAG = "Signature";
    public static final String MEC_TYPE = "DOM";
    private PublicKey publicKey;
    private Certificate certificate;

    //    private static String DEFAULT_FILE = "uidai_offline_publickey_29022019.cer";
    private static String DEFAULT_FILE = "uidai_offline_publickey_29032019.cer";

    public EkycVerification() throws Exception {
        this(new File(Objects.requireNonNull(EkycVerification.class.getClassLoader()
                .getResource(DEFAULT_FILE)).toURI()));
    }

    public EkycVerification(File file) throws Exception {
        this(RsaCreateFactorys.generatePublic(new FileInputStream(file)));
    }

    public EkycVerification(Certificate certificate) {
        this.certificate = certificate;
        this.publicKey = certificate.getPublicKey();

    }

    public boolean checkXMLData(String data) throws Exception {
        return this.verify(data);
    }

    private Document getDomObject(String string) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder builder = dbf.newDocumentBuilder();
        return builder.parse(new InputSource(new StringReader(string)));
    }

    public boolean verify(String xml) throws Exception {
        try {
            Document xmlDoc = getDomObject(xml);
            NodeList nl = xmlDoc.getElementsByTagNameNS(XMLSignature.XMLNS, SIGNATURE_TAG);
            if (nl.getLength() == 0)
                throw new IllegalArgumentException("Cannot find Signature element");

            XMLSignatureFactory fac = XMLSignatureFactory.getInstance(MEC_TYPE);

            DOMValidateContext valContext = new DOMValidateContext(publicKey, nl.item(0));
            XMLSignature signature = fac.unmarshalXMLSignature(valContext);

            return signature.validate(valContext);
        } catch (MarshalException | XMLSignatureException mExp) {
            throw new Exception(mExp);
        }
    }
}
